﻿using System;
using System.Collections.ObjectModel;


namespace advadev.CanOpen
{

    /// <summary>
    /// Represents a remote transmission request transfer
    /// </summary>
    public class RemoteTransmissionRequestTransfer : ITransfer
    {

        /// <summary>for internal use</summary>
        private bool _isTransferCompleteAfterSending;
        /// <summary>for internal use</summary>
        private Collection<CanOpenMessage> _pendingSendMessages = new Collection<CanOpenMessage>();
        /// <summary>for internal use</summary>
        private ReadOnlyCollection<CanOpenMessage> _pendingSendMessagesReference;


        /// <summary>
        /// Initializes a new instance of the RemoteTransmissionRequestTransfer
        /// class by the given parameter
        /// </summary>
        /// <param name="nodeId">
        /// Node id of the device to request a transmission from (must be in the
        /// range of 1..127)
        /// </param>
        /// <param name="cobId">
        /// COB-ID
        /// </param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Will be thrown if the node id is not in the range of 1..127
        /// </exception>
        public RemoteTransmissionRequestTransfer(byte nodeId, UInt16 cobId)
        {
            // check parameter
            if (!(1 <= nodeId && nodeId <= 127))
            {
                throw new ArgumentOutOfRangeException("nodeId", "The node id must be in the range of 1..127");
            }

            // initializaton
            NodeId = nodeId;
            CobId = cobId;
        }


        /// <summary>
        /// Gets or sets the node id
        /// </summary>
        private byte NodeId
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the COB-ID
        /// </summary>
        private UInt16 CobId
        {
            get;
            set;
        }


        /// <summary>
        /// Checks if the given received can open message is a remote
        /// transmission request transfer for the given COB-ID
        /// </summary>
        /// <param name="receivedCanOpenMessage">
        /// Received can open message
        /// </param>
        /// <param name="cobId">
        /// COB-ID
        /// </param>
        /// <returns>
        /// True if the received can open message is a remote transmission
        /// request transfer request, false otherwise
        /// </returns>
        static public bool IsRemoteTransmissionRequestTransfer(CanOpenMessage receivedCanOpenMessage, UInt16 cobId)
        {
            // check parameter
            if (receivedCanOpenMessage == null)
            {
                return false;
            }
            if (receivedCanOpenMessage.IsRemoteTransmissionRequest == false)
            {
                return false;
            }
            
            // check node id
            UInt16 nodeId = receivedCanOpenMessage.CanId;
            nodeId -= cobId;
            if (!(1 <= nodeId && nodeId <= 127))
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Starts the transfer
        /// </summary>
        private void startTransfer()
        {
            UInt16 canId = CobId;
            canId += NodeId;
            _pendingSendMessages.Add(new CanOpenMessage(canId, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, true));
            _isTransferCompleteAfterSending = true;
        }


        #region ITransfer implementation
        /// <summary>
        /// Gets a flag indicating whether the transfer is complete (after
        /// sending the pending send messages)
        /// </summary>
        public bool TransferComplete
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the abort code (null for successful transfers)
        /// </summary>
        public CanOpenAbortCode AbortCode
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the pending send messages
        /// </summary>
        public ReadOnlyCollection<CanOpenMessage> PendingSendMessages
        {
            get
            {
                if (_pendingSendMessagesReference == null)
                {
                    _pendingSendMessagesReference = new ReadOnlyCollection<CanOpenMessage>(_pendingSendMessages);
                }
                return _pendingSendMessagesReference;
            }
        }


        /// <summary>
        /// Starts the transfer
        /// </summary>
        public void Start()
        {
            startTransfer();
        }

        /// <summary>
        /// Times out the transfer
        /// </summary>
        public void TimeOut()
        {
            AbortCode = new CanOpenAbortCode(0x00, 0x00, 0x04, 0x05);
        }

        /// <summary>
        /// Finalizes the transfer
        /// </summary>
        public void FinalizeTransfer()
        {
        }

        /// <summary>
        /// Continues the transfer after sending messages
        /// </summary>
        public void ContinueAfterSendingMessages()
        {
            _pendingSendMessages.Clear();
            if (_isTransferCompleteAfterSending)
            {
                TransferComplete = true;
            }
        }

        /// <summary>
        /// Processes the received message
        /// </summary>
        /// <param name="receivedCanOpenMessage">
        /// Received can open message
        /// </param>
        /// <returns>
        /// True, if the given can open message was related to this transfer,
        /// false otherwise
        /// </returns>
        public bool ProcessReceivedMessage(CanOpenMessage receivedCanOpenMessage)
        {
            return false;
        }
        #endregion ITransfer implementation

    }

}
